home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / kernel / signal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  4.5 KB  |  189 lines

  1. /*
  2.  *  linux/kernel/signal.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  *
  6.  * This file is subject to the terms and conditions of the GNU General Public
  7.  * License.  See the file README.legal in the main directory of this archive
  8.  * for more details.
  9.  */
  10.  
  11. /*
  12.  * 680x0 support by Hamish Macdonald
  13.  */
  14.  
  15. #include <asm/system.h>
  16. #include <asm/segment.h>
  17.  
  18. #include <linux/sched.h>
  19. #include <linux/kernel.h>
  20. #include <linux/traps.h>
  21. #include <linux/signal.h>
  22. #include <linux/errno.h>
  23. #include <linux/wait.h>
  24. #include <linux/ptrace.h>
  25. #include <linux/unistd.h>
  26.  
  27. #define _S(nr) (1<<((nr)-1))
  28.  
  29. #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
  30.  
  31. asmlinkage int do_signal(unsigned long oldmask, struct frame * regs);
  32.  
  33. asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset)
  34. {
  35.     sigset_t new_set, old_set = current->blocked;
  36.     int error;
  37.  
  38.     if (set) {
  39.         error = verify_area(VERIFY_READ, set, sizeof(sigset_t));
  40.         if (error)
  41.             return error;
  42.         new_set = get_fs_long((unsigned long *) set) & _BLOCKABLE;
  43.         switch (how) {
  44.         case SIG_BLOCK:
  45.             current->blocked |= new_set;
  46.             break;
  47.         case SIG_UNBLOCK:
  48.             current->blocked &= ~new_set;
  49.             break;
  50.         case SIG_SETMASK:
  51.             current->blocked = new_set;
  52.             break;
  53.         default:
  54.             return -EINVAL;
  55.         }
  56.     }
  57.     if (oset) {
  58.         error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t));
  59.         if (error)
  60.             return error;
  61.         put_fs_long(old_set, (unsigned long *) oset);
  62.     }
  63.     return 0;
  64. }
  65.  
  66. asmlinkage int sys_sgetmask(void)
  67. {
  68.     return current->blocked;
  69. }
  70.  
  71. asmlinkage int sys_ssetmask(int newmask)
  72. {
  73.     int old=current->blocked;
  74.  
  75.     current->blocked = newmask & _BLOCKABLE;
  76.     return old;
  77. }
  78.  
  79. asmlinkage int sys_sigpending(sigset_t *set)
  80. {
  81.     int error;
  82.     /* fill in "set" with signals pending but blocked. */
  83.     error = verify_area(VERIFY_WRITE, set, 4);
  84.     if (!error)
  85.         put_fs_long(current->blocked & current->signal, (unsigned long *)set);
  86.     return error;
  87. }
  88.  
  89. /*
  90.  * atomically swap in the new signal mask, and wait for a signal.
  91.  */
  92. asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
  93. {
  94.     unsigned long mask;
  95.     struct frame * regs = (struct frame *) &restart;
  96.  
  97.     mask = current->blocked;
  98.     current->blocked = set & _BLOCKABLE;
  99.     regs->d0 = -EINTR;
  100.     while (1) {
  101.         current->state = TASK_INTERRUPTIBLE;
  102.         schedule();
  103.         if (do_signal(mask,regs))
  104.             return -EINTR;
  105.     }
  106. }
  107.  
  108. /*
  109.  * POSIX 3.3.1.3:
  110.  *  "Setting a signal action to SIG_IGN for a signal that is pending
  111.  *   shall cause the pending signal to be discarded, whether or not
  112.  *   it is blocked" (but SIGCHLD is unspecified: linux leaves it alone).
  113.  *
  114.  *  "Setting a signal action to SIG_DFL for a signal that is pending
  115.  *   and whose default action is to ignore the signal (for example,
  116.  *   SIGCHLD), shall cause the pending signal to be discarded, whether
  117.  *   or not it is blocked"
  118.  *
  119.  * Note the silly behaviour of SIGCHLD: SIG_IGN means that the signal
  120.  * isn't actually ignored, but does automatic child reaping, while
  121.  * SIG_DFL is explicitly said by POSIX to force the signal to be ignored..
  122.  */
  123. static void check_pending(int signum)
  124. {
  125.     struct sigaction *p;
  126.  
  127.     p = signum - 1 + current->sigaction;
  128.     if (p->sa_handler == SIG_IGN) {
  129.         if (signum == SIGCHLD)
  130.             return;
  131.         current->signal &= ~_S(signum);
  132.         return;
  133.     }
  134.     if (p->sa_handler == SIG_DFL) {
  135.         if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH)
  136.             return;
  137.         current->signal &= ~_S(signum);
  138.         return;
  139.     }
  140. }
  141.  
  142. asmlinkage int sys_signal(int signum, unsigned long handler)
  143. {
  144.     struct sigaction tmp;
  145.  
  146.     if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
  147.         return -EINVAL;
  148.     if (handler >= TASK_SIZE)
  149.         return -EFAULT;
  150.     tmp.sa_handler = (void (*)(int)) handler;
  151.     tmp.sa_mask = 0;
  152.     tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
  153.     tmp.sa_restorer = NULL;
  154.     handler = (long) current->sigaction[signum-1].sa_handler;
  155.     current->sigaction[signum-1] = tmp;
  156.     check_pending(signum);
  157.     return handler;
  158. }
  159.  
  160. asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
  161.     struct sigaction * oldaction)
  162. {
  163.     struct sigaction new_sa, *p;
  164.  
  165.     if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
  166.         return -EINVAL;
  167.     p = signum - 1 + current->sigaction;
  168.     if (action) {
  169.         memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));
  170.         if (new_sa.sa_flags & SA_NOMASK)
  171.             new_sa.sa_mask = 0;
  172.         else {
  173.             new_sa.sa_mask |= _S(signum);
  174.             new_sa.sa_mask &= _BLOCKABLE;
  175.         }
  176.         if (TASK_SIZE <= (unsigned long) new_sa.sa_handler)
  177.             return -EFAULT;
  178.     }
  179.     if (oldaction) {
  180.         if (!verify_area(VERIFY_WRITE,oldaction, sizeof(struct sigaction)))
  181.             memcpy_tofs(oldaction, p, sizeof(struct sigaction));
  182.     }
  183.     if (action) {
  184.         *p = new_sa;
  185.         check_pending(signum);
  186.     }
  187.     return 0;
  188. }
  189.